// 匹配正则
// 标签名 a-aaa
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
// 命名空间标签 aa:aa-xxx
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
// 开始标签-捕获标签名
const startTagOpen = new RegExp(`^<${qnameCapture}`);
// 结束标签-匹配标签结尾的 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);
// 匹配属性
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
// 匹配标签结束的 >
const startTagClose = /^\s*(\/?)>/;
// 匹配 {{ }} 表达式
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

export function parseHtml(html) {
  let root; // 根元素
  let createParent; // 当前元素的父元素
  let stack = [];

  while (html) {
    let textEnd = html.indexOf("<");
    if (textEnd === 0) {
      const startTagMatch = parseStartTag();
      if (startTagMatch && startTagMatch.tagName) {
        start(startTagMatch.tagName, startTagMatch.attrs);
      }
      const endTagMatch = html.match(endTag);
      if (endTagMatch) {
        end(endTagMatch[1]);
        advance(endTagMatch[0].length);
      }
      continue;
    }
    if (textEnd > 0) {
      let text = html.slice(0, textEnd);
      if (text) {
        advance(text.length);
        content(text);
      }
      continue;
    }
  }
  function parseStartTag() {
    let start = html.match(startTagOpen); // 返回匹配结果或者false
    const match = {
      tagName: start ? start[1] : null,
      attrs: []
    };
    if (start) {
      advance(start[0].length); // 去掉开始标签
    }
    let attr, end;
    while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
      match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] });
      advance(attr[0].length);
    }
    if (end) {
      advance(end[0].length);
    }
    return match;
  }
  function advance(n) {
    html = html.slice(n);
  }
  function start(tag, attrs) {
    let element = createASTElement(tag, attrs);
    if (!root) {
      root = element;
    }
    createParent = element;
    stack.push(element);
  }
  function content(text) {
    // 去掉content里面的空格，不去掉的话，可以保持和html里面写的一样，原样输出
    // text = text.replace(/\s/g, "");
    text = text.trim();
    if (text) {
      createParent.children.push({
        type: 3,
        text
      });
    }
  }
  function end(tag) {
    let element = stack.pop();
    createParent = stack[stack.length - 1];
    if (createParent) {
      element.parent = createParent.tag;
      createParent.children.push(element);
    }
  }
  
  return root;
}

// 创建一个 ast 对象
function createASTElement(tag, attrs) {
  return {
    tag,
    attrs,
    children: [],
    type: 1,
    parent: null
  }
}